{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": [],
      "machine_shape": "hm",
      "gpuType": "L4"
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "source": [
        "# Faster Foundation Models with `torch.compile`"
      ],
      "metadata": {
        "id": "axYlcDTznci4"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Introduction to `torch.compile()`"
      ],
      "metadata": {
        "id": "B-yw8KMWsjfY"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "This guide aims to provide a benchmark on the inference speed-ups introduced with `torch.compile()` with no reduction in model performance for foundation models in 🤗 Transformers.\n",
        "\n",
        "Most used `torch.compile` modes are following:\n",
        "\n",
        "- \"default\" is the default mode, which is a good balance between performance and overhead\n",
        "\n",
        "- \"reduce-overhead\" reduces the overhead of python with CUDA graphs, useful for small batches, consumes a lot of memory. As of now only works for CUDA only graphs which do not mutate inputs.\n",
        "\n",
        "If you have a lot of memory to use, the best speed-up is through `reduce-overhead`. How much speed-up one can get depends on the model, so in this tutorial we will check the most used foundation models."
      ],
      "metadata": {
        "id": "AmmT4aDnqgOB"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## OWLv2\n",
        "\n",
        "OWLv2 is a zero-shot object detection model released by Google Brain. We will load base version."
      ],
      "metadata": {
        "id": "5sCfbPTn7wBE"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "Let's load the model and processor for OWLv2."
      ],
      "metadata": {
        "id": "joeX3J315K0G"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "from PIL import Image\n",
        "import requests\n",
        "\n",
        "url = 'https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/bee.jpg'\n",
        "image = Image.open(requests.get(url, stream=True).raw)"
      ],
      "metadata": {
        "id": "Ztfcdqkul62z"
      },
      "execution_count": 1,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "from transformers import AutoProcessor, Owlv2ForObjectDetection\n",
        "import torch\n",
        "import numpy as np\n",
        "\n",
        "processor = AutoProcessor.from_pretrained(\"google/owlv2-base-patch16-ensemble\")\n",
        "model = Owlv2ForObjectDetection.from_pretrained(\"google/owlv2-base-patch16-ensemble\").to(\"cuda\")\n",
        "\n",
        "texts = [[\"a photo of a bee\", \"a photo of a bird\"]]\n",
        "inputs = processor(text=texts, images=image, return_tensors=\"pt\").to(\"cuda\")"
      ],
      "metadata": {
        "id": "84npPHCQpHZ6",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "f30c41c7-b897-460d-d2a4-a1276bf2263e"
      },
      "execution_count": 2,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/local/lib/python3.10/dist-packages/huggingface_hub/utils/_token.py:89: UserWarning: \n",
            "The secret `HF_TOKEN` does not exist in your Colab secrets.\n",
            "To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.\n",
            "You will be able to reuse this secret in all of your notebooks.\n",
            "Please note that authentication is recommended but still optional to access public models or datasets.\n",
            "  warnings.warn(\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "We can now get to benchmarking. We will benchmark the model itself and the compiled model."
      ],
      "metadata": {
        "id": "3AedkjLu5PRo"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "starter, ender = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True)\n",
        "repetitions = 30\n",
        "timings=np.zeros((repetitions,1))\n",
        "\n",
        "for _ in range(10):\n",
        "    _ = model(**inputs)\n",
        "\n",
        "with torch.no_grad():\n",
        "    for rep in range(repetitions):\n",
        "        torch.cuda.synchronize()\n",
        "        starter.record()\n",
        "        output = model(**inputs)\n",
        "        ender.record()\n",
        "        torch.cuda.synchronize()\n",
        "        curr_time = starter.elapsed_time(ender)\n",
        "        timings[rep] = curr_time\n",
        "\n",
        "mean_syn = np.sum(timings) / repetitions\n",
        "print(mean_syn)\n"
      ],
      "metadata": {
        "id": "RQQSEgkQtXEV",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "8003590b-c4bc-4b3d-9b1b-dade853b8dd8"
      },
      "execution_count": 3,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "255.7331792195638\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "starter, ender = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True)\n",
        "timings=np.zeros((repetitions,1))\n",
        "\n",
        "compiled_model = torch.compile(model, mode=\"reduce-overhead\").to(\"cuda\")\n",
        "\n",
        "for _ in range(30):\n",
        "  with torch.no_grad():\n",
        "    _ = compiled_model(**inputs)\n",
        "\n",
        "\n",
        "with torch.no_grad():\n",
        "    for rep in range(repetitions):\n",
        "        torch.cuda.synchronize()\n",
        "        starter.record()\n",
        "        output = compiled_model(**inputs)\n",
        "        ender.record()\n",
        "        torch.cuda.synchronize()\n",
        "        curr_time = starter.elapsed_time(ender)\n",
        "        timings[rep] = curr_time\n",
        "\n",
        "mean_syn = np.sum(timings) / repetitions\n",
        "print(mean_syn)"
      ],
      "metadata": {
        "id": "bEZiNgaupOx6",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "e5d47875-1e40-4997-e533-94bf0ff34d14"
      },
      "execution_count": 4,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "/usr/lib/python3.10/multiprocessing/popen_fork.py:66: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n",
            "  self.pid = os.fork()\n",
            "/usr/local/lib/python3.10/dist-packages/torch/_inductor/compile_fx.py:124: UserWarning: TensorFloat32 tensor cores for float32 matrix multiplication available but not enabled. Consider setting `torch.set_float32_matmul_precision('high')` for better performance.\n",
            "  warnings.warn(\n",
            "skipping cudagraphs due to skipping cudagraphs due to cpu device. Found from : \n",
            "   File \"/usr/local/lib/python3.10/dist-packages/transformers/models/owlv2/modeling_owlv2.py\", line 1711, in forward\n",
            "    pred_boxes = self.box_predictor(image_feats, feature_map)\n",
            "  File \"/usr/local/lib/python3.10/dist-packages/transformers/models/owlv2/modeling_owlv2.py\", line 1374, in box_predictor\n",
            "    box_bias = self.box_bias.to(feature_map.device)\n",
            "\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "154.6884775797526\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "We got nearly 40 percent speed-up! You can also increase the batch size and see how much further speed-up you can get."
      ],
      "metadata": {
        "id": "d_0d7DwN6gBt"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "texts = [[\"a photo of a bee\", \"a photo of a bird\"] for _ in range(8)]\n",
        "images = [image for _ in range(8)]\n",
        "inputs = processor(text=texts, images=image, return_tensors=\"pt\").to(\"cuda\")"
      ],
      "metadata": {
        "id": "exKoOptB61UL"
      },
      "execution_count": 11,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "starter, ender = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True)\n",
        "repetitions = 30\n",
        "timings=np.zeros((repetitions,1))\n",
        "\n",
        "for _ in range(10):\n",
        "    _ = model(**inputs)\n",
        "\n",
        "with torch.no_grad():\n",
        "    for rep in range(repetitions):\n",
        "        torch.cuda.synchronize()\n",
        "        starter.record()\n",
        "        output = model(**inputs)\n",
        "        ender.record()\n",
        "        torch.cuda.synchronize()\n",
        "        curr_time = starter.elapsed_time(ender)\n",
        "        timings[rep] = curr_time\n",
        "\n",
        "mean_syn = np.sum(timings) / repetitions\n",
        "print(mean_syn)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "EFj9Pgra7Km8",
        "outputId": "5fefb8c0-9e86-478c-e9e2-0dbc0fa8a37b"
      },
      "execution_count": 12,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "269.3023401896159\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "starter, ender = torch.cuda.Event(enable_timing=True), torch.cuda.Event(enable_timing=True)\n",
        "timings=np.zeros((repetitions,1))\n",
        "\n",
        "compiled_model = torch.compile(model, mode=\"reduce-overhead\").to(\"cuda\")\n",
        "\n",
        "for _ in range(30):\n",
        "  with torch.no_grad():\n",
        "    _ = compiled_model(**inputs)\n",
        "\n",
        "\n",
        "with torch.no_grad():\n",
        "    for rep in range(repetitions):\n",
        "        torch.cuda.synchronize()\n",
        "        starter.record()\n",
        "        output = compiled_model(**inputs)\n",
        "        ender.record()\n",
        "        torch.cuda.synchronize()\n",
        "        curr_time = starter.elapsed_time(ender)\n",
        "        timings[rep] = curr_time\n",
        "\n",
        "mean_syn = np.sum(timings) / repetitions\n",
        "print(mean_syn)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "OuQZmgTK7UCo",
        "outputId": "7184eb1d-b545-4bb6-b544-3effd5c2545a"
      },
      "execution_count": 13,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "159.77137603759766\n"
          ]
        }
      ]
    }
  ]
}